﻿using System;
using System.Collections;
using System.Text;
using System.IO;

using iTextSharp.text;
using iTextSharp.text.pdf;

namespace iPdf
{
    class PdfMerger : Actor<MergeItem, PdfLetOption>
    {
        #region Fields
        protected string path;
        protected FileStream outputStream;
        protected PdfCopy copyCat;
        protected Document document;
        protected ArrayList bookmarks;
        protected int totalNumOfPages;
        #endregion

        #region Methods

        protected override void Prepare()
        {
            path = Helper.ShowSaveFileDialog(FileFormat.PdfFormat,
                        "Merged" + Global.PdfExt);
            if (string.IsNullOrEmpty(path))
            {
                throw new ActionCancelled();
            }

            outputStream = Helper.OpenWrite(path);

            bookmarks = new ArrayList();
            totalNumOfPages = 0;
        }

        protected override void Work()
        {
            base.Work();

            PdfReader reader = null;
            try
            {
                reader = GetReader();

                if (copyCat == null)
                {
                    document = new Document();
                    copyCat = new PdfCopy(document, outputStream);
                    document.Open();
                }

                int numOfPages = AddPages(reader);

                if (pageOption.Bookmark)
                {
                    //extract the bookmarks by page range
                    Hashtable destinations = PdfPageRearranger.GetNamedDestinations(reader);
                    ArrayList bookmarkByPageRange = PdfPageRearranger.ProcessBookmarks(SimpleBookmark.GetBookmark(reader), destinations,
                                                                     workItem.From, workItem.To, numOfPages, totalNumOfPages + 1 - workItem.From);
                    if (bookmarkByPageRange != null &&
                        bookmarkByPageRange.Count > 0)
                    {
                        bookmarks.AddRange(bookmarkByPageRange);
                    }
                    else
                    {
                        bookmarks.Add(
                            SharpHelper.CreateBookmarkByPageNo(totalNumOfPages + 1,
                            Path.GetFileNameWithoutExtension(workItem.Source)));
                    }
                }

                totalNumOfPages += numOfPages;
            }
            finally
            {
                SharpHelper.ClosePdf(reader, null);
            }
        }

        protected virtual PdfReader GetReader()
        {
            return new PdfReader(File.OpenRead(workItem.Source));
        }

        protected virtual int AddPages(PdfReader reader)
        {
            PdfPageRearranger.AddPages(reader, copyCat, workItem.From, workItem.To,
                                               workItem.Source);

            return workItem.To - workItem.From + 1;
        }

        protected override void Finish()
        {
            if (copyCat != null && bookmarks != null && bookmarks.Count > 0)
            {
                copyCat.Outlines = bookmarks;
            }

            if (totalNumOfPages == 0)
            {
                //something went wrong, we add a informative page to show user we're sorry
                document = new Document();
                PdfWriter writer = PdfWriter.GetInstance(document, outputStream);
                document.Open();
                document.Add(new Paragraph("Oops, it seems that " + Global.ApplicationName +
                    " couldn't merge these files. Please make sure that all the files is accessible and not encrypted without page extraction permission."));
                SharpHelper.ClosePdf(document, writer, outputStream, null, null);
                document = null;
                outputStream = null;
                copyCat = null;
            }

            SharpHelper.ClosePdf(document, copyCat, outputStream);
            outputStream = null;
            copyCat = null;
            document = null;
            bookmarks = null;

            base.Finish();

            Helper.StartFile(path);
        }

        #endregion
    }
}
